package com.link_with_health.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.link_with_health.common.Page;
import com.link_with_health.common.Result;
import com.link_with_health.common.TokenMap;
import com.link_with_health.exception.NullQueryResultException;
import com.link_with_health.model.AdminLogEntity;
import com.link_with_health.model.AdminUserEntity;
import com.link_with_health.model.DepartmentsEntity;
import com.link_with_health.model.DoctorEntity;
import com.link_with_health.model.InquiryEntity;
import com.link_with_health.model.PatientEntity;
import com.link_with_health.model.UserEntity;
import com.link_with_health.model.WaitingQueueEntity;
import com.link_with_health.service.AdminLogService;
import com.link_with_health.service.DoctorService;
import com.link_with_health.service.PatientService;
import com.link_with_health.service.WaitingQueueService;
import com.link_with_health.utils.JsonUtil;
import com.link_with_health.webSocket.WaitingQueueServer;
import org.apache.ibatis.jdbc.Null;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Controller
@RequestMapping("/api/waitingQueue/")
public class WaitingQueueController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final String AUTH_TOKEN = "Authorization";
    private TokenMap tokenMap = TokenMap.getInstance();

    @Resource(name = "waitingQueueService")
    WaitingQueueService waitingQueueService;

    @Resource(name = "doctorService")
    DoctorService doctorService;

    @Resource(name = "adminLogService")
    AdminLogService adminLogService;

    @Resource(name = "patientService")
    PatientService patientService;

    /**
     * 获取候诊队列信息
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/findQueueInfo")
    @ResponseBody
    public Result findQueueInfo(@RequestBody JSONObject json
            , HttpServletRequest request){
        String msg = "请求失败 无授权信息";
        String token = request.getHeader(AUTH_TOKEN);
        tokenMap.containsKey(token);

        String method = json.getString("method");
        try {
            String paramsStr = json.getJSONObject("params")
                    .toJSONString();

            HashMap<String,Object> params = JsonUtil.json2obj(paramsStr
                    , HashMap.class);

            return method(method,params);

        } catch (Exception e){
            logger.error("[error in find queue]",e);
            msg = "获取失败";
            if(e instanceof NullQueryResultException){
                return Result.notResult("无候诊信息 查找结果","NULL");
            }
        }
        return Result.fail(msg);
    }

    /**
     * 修改候诊队列信息
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/modifyQueueInfo")
    @ResponseBody
    public Result modifyQueueInfo(@RequestBody JSONObject json
            , HttpServletRequest request){

        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";

        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[get patient info failed]");
            return Result.fail(msg);
        }

        Integer adminId = Math.toIntExact(tokenMap.get(token)
                instanceof AdminUserEntity
                ? ((AdminUserEntity) tokenMap.get(token)).getAdminID()
                : ((UserEntity) tokenMap.get(token)).getUserId());

        try {
            WaitingQueueEntity entity = JsonUtil
                    .json2obj(json.toJSONString()
                            , WaitingQueueEntity.class);

            String queue = entity.getPatientQueue();
            String patients = "";
            if(queue != null && !"##".equals(queue)){
                //调用checkQueue检测
                patients = this.checkQueue(queue);
                System.out.println(patients);
                if(!"[]".equals(patients))
                    return Result.fail("输入的患者id有误"+ patients);
            }


            WaitingQueueEntity oldEntity = waitingQueueService
                    .getWaitingQueueById(entity.getQueueId());

            waitingQueueService.changeWaitingQueue(entity);

            entity = waitingQueueService
                    .getWaitingQueueById(entity.getQueueId());

            //备份
            String object = JsonUtil.obj2json(oldEntity);
            AdminLogEntity log = new AdminLogEntity(0L, adminId
                    , "修改", "waitingQueue", object);

            return Result.success("操作成功",entity);

        } catch (Exception e){
            logger.error("[modify waitingQueue failed]",e);
            msg = "操作失败";
        }

        return Result.fail(msg);
    }

    /**
     * 修改候诊队列信息
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/addQueueInfo")
    @ResponseBody
    public Result addQueueInfo(@RequestBody JSONObject json
            , HttpServletRequest request){

        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";

        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[get patient info failed]");
            return Result.fail(msg);
        }
        Integer adminId = Math.toIntExact(tokenMap.get(token)
                instanceof AdminUserEntity
                ? ((AdminUserEntity) tokenMap.get(token)).getAdminID()
                : ((UserEntity) tokenMap.get(token)).getUserId());


        try {

            WaitingQueueEntity entity = JsonUtil.json2obj(json.toJSONString()
                    , WaitingQueueEntity.class);

            //判断书写
            String queue = entity.getPatientQueue();
            String patients = "";
            if(queue != null && !"##".equals(queue)){
                //调用checkQueue检测
                patients = this.checkQueue(queue);
                if(!"[]".equals(patients));
                return Result.fail("输入的患者id有误"+ patients);
            }

            waitingQueueService.addWaitingQueue(entity);
            entity = waitingQueueService
                    .getWaitingQueueById(entity.getQueueId());

            //备份
            String object = JsonUtil.obj2json(entity);
            AdminLogEntity log = new AdminLogEntity(0L, adminId
                    , "增加", "waitingQueue", object);

            adminLogService.addAdminLog(log);

            return Result.success("成功修改", entity);


        } catch (Exception e){
            logger.error("[add waitingQueue info failed]",e);
            msg = "操作失败 请检查输入的参数";
        }

        return Result.fail(msg);
    }

    /**
     * 删除候诊队列信息
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/deleteQueueInfo")
    @ResponseBody
    public Result deleteQueueInfo(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";

        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[get patient info failed]");
            return Result.fail(msg);
        }

        Integer adminId = Math.toIntExact(tokenMap.get(token)
                instanceof AdminUserEntity
                ? ((AdminUserEntity) tokenMap.get(token)).getAdminID()
                : ((UserEntity) tokenMap.get(token)).getUserId());

        int errorNumber = 0;

        try {


            Long[] ids = json.getObject("ids",Long[].class);
            //备份
            StringBuffer oldEntity = new StringBuffer();

            for(Long idBk : ids){
                WaitingQueueEntity entity = waitingQueueService
                        .getWaitingQueueById(idBk);

                oldEntity.append("\n").append(JsonUtil.obj2json(entity));

                try{
                    waitingQueueService.deleteWaitingQueue(idBk);
                }catch (Exception e){
                    logger.error("[delete waiting info failed" +
                            " =>"+idBk+"]",e);
                    errorNumber++;
                }
            }

            AdminLogEntity log = new AdminLogEntity(0L, adminId
                    , "删除", "waitingQueue"
                    , oldEntity.toString());

            adminLogService.addAdminLog(log);

            if(errorNumber == 0){
                return Result.success("操作成功", "NULL");
            }

        } catch (Exception e){
            logger.error("[failed to delete total=> "+errorNumber+"]",e);
            msg = "失败删除条数"+errorNumber;
        }

        return Result.fail(msg);
    }

    /**
     * 患者加入候诊对列
     * @param json 数据 userId patientId queueId
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/lineUp")
    @ResponseBody
    public Result lineUp(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签校验失败";

        if(token == null || !tokenMap.containsKey(token)){
            logger.error("[line up failed by token]");
            return Result.fail(msg);
        }

        try {
            Long userId = ((UserEntity) tokenMap.get(token))
                    .getUserId();

            //校验是否为当前用户
            if(userId.equals(json.getLong("userId"))){
                Long queueId = json.getLong("queueId");
                Long patientId = json.getLong("patientId");

                WaitingQueueEntity entity = waitingQueueService
                        .getWaitingQueueById(queueId);
                String queue = entity.getPatientQueue();


                if(queue.isEmpty()
                        || queue.indexOf(queue.length()-1) != '#'){
                    queue = queue + "#";
                }
                //检测队列情况
                int lineLength = queue.split("#").length - 1;
                if(lineLength > entity.getMaxQueue()
                        || entity.getMaxAppointment() == 0){
                    logger.warn("[can't not line up "+
                            "queue: "+lineLength +" "+"]");

                    return Result.notResult("当前候诊条件无法加入","NULL");
                }

                queue = queue + patientId + "#";
                entity.setPatientQueue(queue);
                entity.setMaxAppointment(
                        entity.getMaxAppointment()-1);
                //修改数据库数据
                waitingQueueService.changeWaitingQueue(entity);
                //广播
                WaitingQueueServer.modifyQueue(JSON.toJSONString(entity)
                        ,entity.getQueueId());

                return Result.success("操作成功",entity);
            }


        } catch (Exception e){
            logger.error("[failed to line up]",e);
            msg = "加入队列失败";
        }

        return Result.fail(msg);
    }

    /**
     * 取消排队
     * @param request 请求
     * @return 返回数据
     */
    @PostMapping("/cancelQueue")
    @ResponseBody
    public Result cancelQueue(@RequestBody JSONObject json
            , HttpServletRequest request){

        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签校验失败";

        if(token == null || !tokenMap.containsKey(token)){
            logger.error("[line up failed by token]");
            return Result.fail(msg);
        }
        try{
            //获取候诊id
            Long queueId = json.getLong("queueId");

            WaitingQueueEntity entity = waitingQueueService
                    .getWaitingQueueById(queueId);

            String queue = entity.getPatientQueue();
            //最大预约数
            int length = entity.getMaxAppointment();

            //获取当前账号的id
            Long userId = ((UserEntity)tokenMap.get(token)).getUserId();

            //获取账号的患者信息
            List<PatientEntity> list = null;
            try{
                list = patientService.getPatientByUserId(userId);
            }catch(Exception e){
                logger.warn("[not patient info]",e);
            }
            //与候诊信息中的患者队列比较，将本账号的患者信息去除
            if(list != null){
                for(PatientEntity patient:list){
                    String id = String.valueOf(patient.getPatientId());
                    //查看是否在队列
                    if(queue.contains(id)){
                        queue=queue.replaceAll(id+"#","");
                        logger.info("[ "+ id +"get off]");
                        //恢复当日预约数
                        length++;
                    }
                }
                if(queue.indexOf(queue.length()) != '#')
                    queue = queue + '#';

                entity.setPatientQueue(queue);
                entity.setMaxAppointment(length);
            }

            //修改数据库数据
            waitingQueueService.changeWaitingQueue(entity);
            //广播
            WaitingQueueServer.modifyQueue(JSON.toJSONString(entity)
                    ,entity.getQueueId());

            return Result.success("操作成功",entity);
        }catch(Exception e){
            logger.error("[failed to cancel queue]",e);
            msg = "取消失败";
        }

        return Result.fail(msg);
    }

    /**
     * 更新候诊信息
     * @param json doctorId queueId
     * @param request 请求
     * @return 操作结果
     */
    @PostMapping("/nextPatient")
    @ResponseBody
    public Result nextPatient(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签失败";

        if(token == null || !tokenMap.containsKey(token)){
            logger.error("[operate failed by token]");
            return Result.fail(msg);
        }
        try{
            Long userId = ((UserEntity)tokenMap.get(token))
                    .getUserId();
            Long drId = doctorService
                    .getDoctorsByUserId(userId).getDrId();
            if( drId != null && drId.equals
                    (json.getLong("doctorId"))){
                Long queueId = json.getLong("queue");

                WaitingQueueEntity entity = waitingQueueService
                        .getWaitingQueueById(queueId);

                // 去掉第一个患者信息
                String queue = entity.getPatientQueue();
                queue = queue.replaceFirst("#(.+?)#","#");
                entity.setPatientQueue(queue);

                waitingQueueService.changeWaitingQueue(entity);
                //广播
                WaitingQueueServer.modifyQueue(
                        JSON.toJSONString(entity),entity.getQueueId());

                return Result.success("更新候诊信息",entity);

            }

        }catch(Exception e){
            logger.error("[operate failed by]");
            msg = "叫号失败";
        }

        return Result.fail(msg);
    }

    /**
     * 设置候诊对列
     * @param json 数据 waitingQueueId
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/selectWaitingQueueById")
    @ResponseBody
    public Result selectWaitingQueueById(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        tokenMap.containsKey(token);

        String msg = "请求失败";
        try {
            Long id = json.getLong("waitingQueueId");
            WaitingQueueEntity entity = waitingQueueService
                    .getWaitingQueueById(id);

            return Result.success(entity);

        } catch (Exception e){
            logger.error("[get waitingQueue Fail]",e);
            if(e instanceof NullQueryResultException) {
                msg = "无数据查询结果";
                return Result.notResult(msg,null);
            }
        }

        return Result.fail(msg);
    }

    /**
     * 设置候诊对列
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @PostMapping("/editQueueSetting")
    @ResponseBody
    public Result editQueueSetting(@RequestBody JSONObject json
            , HttpServletRequest request){
        String msg = "验签失败";
        String token = request.getHeader(AUTH_TOKEN);
        if(token == null || !tokenMap.containsKey(token)){
            logger.error("failed to edit waitingQueue");
            return Result.fail(msg);
        }

        try {
            Long userId = ((UserEntity) tokenMap.get(token))
                    .getUserId();
            Long doctorId = doctorService
                    .getDoctorsByUserId(userId).getDrId();

            WaitingQueueEntity entity = JsonUtil.json2obj(json.toJSONString(),WaitingQueueEntity.class);
            entity.setIsOpen(true);

            //校验是否为本用户操作
            if(doctorId.equals(entity.getDoctorId())){
                waitingQueueService.changeWaitingQueue(entity);

                //广播给候诊室内的用户
                WaitingQueueServer.modifyQueue(json.toJSONString()
                        ,entity.getQueueId());

                return Result.success("修改成功",entity);
            }


        } catch (Exception e){
            logger.error("[edit waitingQueue failed]");
            msg = "编辑失败";
        }

        return Result.fail(msg);
    }

    /**
     *
     * @param json patientQueue
     * @param request 请求
     * @return 返回结果
     */
    @RequestMapping("/getPatientQueue")
    @ResponseBody
    public Result getPatientQueue(@RequestBody JSONObject json, HttpServletRequest request){
        String msg = "验签失败";
        String token = request.getHeader(AUTH_TOKEN);
        if(token == null || !tokenMap.containsKey(token)){
            logger.error("failed to edit waitingQueue");
            return Result.fail(msg);
        }

        try{
            String queueStr = json.getString("patientQueue");
            List<PatientEntity> list = new ArrayList<>();

            if(queueStr != null) {
                String[] queue = queueStr.split("#");
                if (queue.length > 1)
                    for (int index = 1; index < queue.length; index++) {
                        try {
                            list.add(patientService
                                    .getPatientByPatientId(Long.valueOf(queue[index])));
                        } catch (Exception e) {
                            logger.warn("[patient id not found " + queue[index] + " ]");
                        }
                    }
            }
            return Result.success("获取成功",list);

        }catch(Exception e){
            logger.error("",e);
            msg = "获取患者信息失败";
        }

        return Result.fail(msg);
    }

    private String checkQueue(String patientQueue){

        String[] queue = patientQueue.split("#");
        int index = 0;
        StringBuilder buffer = new StringBuilder();
        buffer.append("[");

        if(queue.length > 1) {
            for (index = 1; index < queue.length; index++) {
                try {
                    patientService.getPatientByPatientId(Long.valueOf(queue[index]));
                } catch (Exception e) {
                    logger.warn("[patient id not found " + queue[index] + " ]");
                    buffer.append(" ").append(queue[index]);
                }
            }
            buffer.append("]");

        }

        return buffer.toString();
    }


    /**
     * 根据method选择筛选不同数据的方法
     * @param method 方法
     * @param params 筛选参数
     * @return 封装好的数据
     * @throws Exception 异常
     */
    private Result method(String method, HashMap<String,Object> params)
            throws Exception{
        List<WaitingQueueEntity> list = null;
        String msg = "数据获取失败";

        switch(method){
            case "all": case "all-page":{
                list = waitingQueueService.getAllWaitingQueue();
            }
                break;

            case "doctorId":{
                String doctorId = String.valueOf(params.get("doctorId"));
                list = waitingQueueService
                        .getWaitingQueueByDoctor(Long.valueOf(doctorId));
            }
                break;

            case "id-page": {
                String id = String.valueOf(params.get("id"));
                try{
                    list = waitingQueueService
                            .getWaitingQueueByDoctor(Long.valueOf(id));
                }catch(Exception e){
                    logger.warn("[not result by search doctorId]");
                }
                try{ //效率不行
                    if(list == null)
                        list = waitingQueueService
                                .getWaitingQueueByPatient(Long.valueOf(id));
                    else
                        list.addAll(waitingQueueService
                                .getWaitingQueueByPatient(Long.valueOf(id)));

                }catch(Exception e){
                    logger.warn("[not result by search patient]");
                }
                try{
                    if(list == null)
                        list = new ArrayList<WaitingQueueEntity>();
                    list.add(waitingQueueService.getWaitingQueueById(Long.valueOf(id)));

                    list = list.stream().distinct().collect(Collectors.toList());

                } catch(Exception e){
                    logger.warn("[result by search waitingQueueId]");
                }
            }
                break;

            case "name-page":{
                String name = String.valueOf(params.get("name"));
                if("".equals(name) || name == null)
                    throw new NullPointerException("[name is invalid]");

                list = waitingQueueService
                        .getAllWaitingQueue()
                        .stream()
                        .filter(item -> (item.getDoctorName() != null
                                && item.getDoctorName().contains(name)))
                        .collect(Collectors.toList());
            }
            break;
            default:
                logger.error("unknown method=>" + method);
                return Result.fail("未知查找方法");
        }
        if(list == null || list.isEmpty())
            throw new NullQueryResultException("[not result fo inquiry]");

        //封装 带页数数据
        if(method.contains("page")){

            Integer current = Integer.valueOf(String.valueOf(params.get("current"))) ;
            Integer size = Integer.valueOf(String.valueOf(params.get("size")));
            Page<WaitingQueueEntity> page = new Page<>(list,size,current);
            return Result.success(page.getPageDate());
        }

        return Result.success(list);

    }
}
